/**
 * @(#)SystemExecutionServiceImpl.java Jan 22, 2010
 *   
 * Copyright  (c) 2009-2010 Wilmar IT Service,  Inc.   
 * All  rights  reserved.   
 * TODO
 */

package com.wilmar.process.core.services.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.jbpm.api.Execution;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.task.Task;

import com.wilmar.process.core.services.api.ISystemExecutionService;
import com.wilmar.process.core.services.api.ISystemProcessLogService;
import com.wilmar.process.core.services.api.ISystemTaskInstanceService;
import com.wilmar.process.entity.InstanceOperateOpinion;
import com.wilmar.process.entity.ProcessLog;
import com.wilmar.process.entity.User;
import com.wilmar.process.entity.vo.ExecutionVO;
import com.wilmar.process.enumerate.EnumProcessLogLevel;
import com.wilmar.process.enumerate.EnumProcessOperateOpinionType;
import com.wilmar.process.exception.ObjectNotFoundException;
import com.wilmar.process.exception.PermissionDeniedException;

/**
 * @author MaKuBEX Email:makubexnet@gmail.com
 * @version 2.0.1
 */
public class SystemExecutionServiceImpl implements ISystemExecutionService {

	private ProcessEngine processEngine;
	private ISystemProcessLogService systemProcessLogService;
	private ISystemTaskInstanceService systemTaskInstanceService;

	/**
	 * @see com.wilmar.process.core.services.api.ISystemExecutionService#signalExecutionById(java.lang.String,
	 *      com.wilmar.process.entity.User)
	 */
	public ProcessInstance signalExecutionById(String executionId, User user,
			InstanceOperateOpinion opinion) {
		Execution exe = this.processEngine.getExecutionService().findExecutionById(executionId);
		ProcessInstance instance = null;
		if (exe.getIsProcessInstance()) {
			List<Task> tasks = this.systemTaskInstanceService
					.getCurrentActiveTaskInstanceList(executionId);
			for (Task task : tasks) {
				try {
					this.systemTaskInstanceService.completeTask(task.getId(),
							user, opinion, null, true);
				} catch (PermissionDeniedException e) {
					e.printStackTrace();
				}
			}
		} else {
			instance = this.processEngine.getExecutionService().signalExecutionById(executionId);
		}
		this.saveLog(user, exe, opinion, null);
		return instance;
	}

	private void saveLog(User user, Execution exe,
			InstanceOperateOpinion opinion, String outCome) {
		ProcessLog aLog = new ProcessLog();
		aLog.setEnterTime(new Date());
		aLog.setLogLevel(EnumProcessLogLevel.LOG_LEVEL_TWO);
		aLog.setOpinionType(EnumProcessOperateOpinionType.MESSAGE);
		aLog.setOperator(user.getId());
		aLog.setOperatorName(user.getName());
		aLog.setOuterSystem(user.getOuterSystem());
		aLog.setExecutionId(exe.getId());
		aLog.setProcessInstanceId(exe.getProcessInstance().getId());
		if (outCome != null)
			aLog.setOutCome(outCome);
		aLog.setLeaveTime(new Date());
		this.systemProcessLogService.saveProcessLog(aLog);
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemExecutionService#
	 *      signalExecutionById(java.lang.String, java.util.Map,
	 *      com.wilmar.process.entity.User)
	 */
	public ProcessInstance signalExecutionById(String executionId,
			Map<String, ?> variables, User user, InstanceOperateOpinion opinion) {
		Execution exe = this.processEngine.getExecutionService().findExecutionById(executionId);
		ProcessInstance instance = null;
		if (exe.getIsProcessInstance()) {
			List<Task> tasks = this.systemTaskInstanceService
					.getCurrentActiveTaskInstanceList(executionId);
			for (Task task : tasks) {
				try {
					this.systemTaskInstanceService.completeTask(task.getId(),
							user, opinion, variables, true);
				} catch (PermissionDeniedException e) {
					e.printStackTrace();
				}
			}
		} else {
			instance = this.processEngine.getExecutionService().signalExecutionById(executionId,
					variables);
		}
		this.saveLog(user, exe, opinion, null);
		return instance;
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemExecutionService#
	 *      signalExecutionById(java.lang.String, java.lang.String,
	 *      com.wilmar.process.entity.User)
	 */
	public ProcessInstance signalExecutionById(String executionId,
			String signalName, User user, InstanceOperateOpinion opinion) {
		Execution exe = this.processEngine.getExecutionService().findExecutionById(executionId);
		ProcessInstance instance = null;
		if (exe.getIsProcessInstance()) {
			List<Task> tasks = this.systemTaskInstanceService
					.getCurrentActiveTaskInstanceList(executionId);
			for (Task task : tasks) {
				try {
					this.systemTaskInstanceService.completeTask(task.getId(),
							signalName, user, opinion, null, true);
				} catch (PermissionDeniedException e) {
					e.printStackTrace();
				}
			}
		} else {
			instance = this.processEngine.getExecutionService().signalExecutionById(executionId,
					signalName);
		}
		this.saveLog(user, exe, opinion, signalName);
		return instance;
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemExecutionService#
	 *      signalExecutionById(java.lang.String, java.util.Map,
	 *      java.lang.String, com.wilmar.process.entity.User)
	 */
	public ProcessInstance signalExecutionById(String executionId,
			Map<String, ?> variables, String signalName, User user,
			InstanceOperateOpinion opinion) {
		Execution exe = this.processEngine.getExecutionService().findExecutionById(executionId);
		ProcessInstance instance = null;
		if (exe.getIsProcessInstance()) {
			List<Task> tasks = this.systemTaskInstanceService
					.getCurrentActiveTaskInstanceList(executionId);
			for (Task task : tasks) {
				try {
					this.systemTaskInstanceService.completeTask(task.getId(),
							signalName, user, opinion, variables, true);
				} catch (PermissionDeniedException e) {
					e.printStackTrace();
				}
			}
		} else {
			instance = this.processEngine.getExecutionService().signalExecutionById(executionId,
					signalName, variables);
		}
		this.saveLog(user, exe, opinion, signalName);
		return instance;
	}

	/**
	 * @see com.wilmar.process.core.services.api.IBaseService#convertToVO(java.lang.Object)
	 */
	public ExecutionVO convertToVO(Execution entity) {
		ExecutionVO vo = new ExecutionVO(entity);
		return vo;
	}

	/**
	 * @see com.wilmar.process.core.services.api.IBaseService#convertToVOList(java.util.Collection)
	 */
	public List<ExecutionVO> convertToVOList(
			Collection<Execution> entityCollection) {
		List<ExecutionVO> voList = new ArrayList<ExecutionVO>(entityCollection
				.size());
		for (Execution exe : entityCollection) {
			voList.add(this.convertToVO(exe));
		}
		return voList;
	}

	/**
	 * @return the systemProcessLogService
	 */
	public ISystemProcessLogService getSystemProcessLogService() {
		return systemProcessLogService;
	}

	/**
	 * @param systemProcessLogService
	 *            the systemProcessLogService to set
	 */
	public void setSystemProcessLogService(
			ISystemProcessLogService systemProcessLogService) {
		this.systemProcessLogService = systemProcessLogService;
	}

	/**
	 * @see com.wilmar.process.core.services.api.ISystemExecutionService#getDetailById(java.lang.String)
	 */
	public Execution getDetailById(String executionId)
			throws ObjectNotFoundException {
		Execution execution = this.processEngine.getExecutionService()
				.findExecutionById(executionId);
		if (execution == null)
			throw new ObjectNotFoundException("There is no execution's id is:"
					+ executionId);
		return execution;
	}

	/**
	 * @return the systemTaskInstanceService
	 */
	public ISystemTaskInstanceService getSystemTaskInstanceService() {
		return systemTaskInstanceService;
	}

	/**
	 * @param systemTaskInstanceService
	 *            the systemTaskInstanceService to set
	 */
	public void setSystemTaskInstanceService(
			ISystemTaskInstanceService systemTaskInstanceService) {
		this.systemTaskInstanceService = systemTaskInstanceService;
	}

	/**
	 * @return the processEngine
	 */
	public ProcessEngine getProcessEngine() {
		return processEngine;
	}

	/**
	 * @param processEngine the processEngine to set
	 */
	public void setProcessEngine(ProcessEngine processEngine) {
		this.processEngine = processEngine;
	}

}
